package com.atom.module.mvi.util

import io.reactivex.rxjava3.core.Observable
import io.reactivex.rxjava3.core.ObservableSource
import io.reactivex.rxjava3.functions.BiFunction

data class Result2<out T1, out T2>(
    val t1: T1, val t2: T2
)

fun <T1, T2> combineLatest(
    o1: ObservableSource<T1>, o2: ObservableSource<T2>
): ObservableSource<Result2<T1, T2>> =
    Observable.combineLatest(o1, o2, object : BiFunction<T1, T2, Result2<T1, T2>> {
        override fun apply(t1: T1, t2: T2): Result2<T1, T2> {
            return Result2(t1, t2)
        }
    })


data class Result3<out T1, out T2, out T3>(
    val t1: T1, val t2: T2, val t3: T3
)

fun <T1, T2, T3> combineLatest(
    o1: ObservableSource<T1>, o2: ObservableSource<T2>, o3: ObservableSource<T3>
): ObservableSource<Result3<T1, T2, T3>> {
    return Observable.combineLatest(
        o1,
        o2,
        o3,
        object : Function3<T1, T2, T3, Result3<T1, T2, T3>> {
            override fun invoke(p1: T1, p2: T2, p3: T3): Result3<T1, T2, T3> {
                return Result3(p1, p2, p3)
            }
        })
}

data class Result4<out T1, out T2, out T3, out T4>(
    val t1: T1, val t2: T2, val t3: T3, val t4: T4
)

fun <T1, T2, T3, T4> combineLatest(
    o1: ObservableSource<T1>,
    o2: ObservableSource<T2>,
    o3: ObservableSource<T3>,
    o4: ObservableSource<T4>
): ObservableSource<Result4<T1, T2, T3, T4>> {
    return Observable.combineLatest(
        o1,
        o2,
        o3,
        o4,
        object : Function4<T1, T2, T3, T4, Result4<T1, T2, T3, T4>> {
            override fun invoke(p1: T1, p2: T2, p3: T3, p4: T4): Result4<T1, T2, T3, T4> {
                return Result4(p1, p2, p3, p4)
            }
        })
}


data class Result5<out T1, out T2, out T3, out T4, out T5>(
    val t1: T1, val t2: T2, val t3: T3, val t4: T4, val t5: T5
)

fun <T1, T2, T3, T4, T5> combineLatest(
    o1: ObservableSource<T1>,
    o2: ObservableSource<T2>,
    o3: ObservableSource<T3>,
    o4: ObservableSource<T4>,
    o5: ObservableSource<T5>
): ObservableSource<Result5<T1, T2, T3, T4, T5>> {
    return Observable.combineLatest(
        o1,
        o2,
        o3,
        o4,
        o5,
        object : Function5<T1, T2, T3, T4, T5, Result5<T1, T2, T3, T4, T5>> {
            override fun invoke(
                p1: T1, p2: T2, p3: T3, p4: T4, p5: T5
            ): Result5<T1, T2, T3, T4, T5> {
                return Result5(p1, p2, p3, p4, p5)
            }
        })
}


data class Result6<out T1, out T2, out T3, out T4, out T5, out T6>(
    val t1: T1, val t2: T2, val t3: T3, val t4: T4, val t5: T5, val t6: T6
)

fun <T1, T2, T3, T4, T5, T6> combineLatest(
    o1: ObservableSource<T1>,
    o2: ObservableSource<T2>,
    o3: ObservableSource<T3>,
    o4: ObservableSource<T4>,
    o5: ObservableSource<T5>,
    o6: ObservableSource<T6>
): ObservableSource<Result6<T1, T2, T3, T4, T5, T6>> {
    return Observable.combineLatest(o1,
        o2,
        o3,
        o4,
        o5,
        o6,
        object : Function6<T1, T2, T3, T4, T5, T6, Result6<T1, T2, T3, T4, T5, T6>> {
            override fun invoke(
                p1: T1, p2: T2, p3: T3, p4: T4, p5: T5, p6: T6
            ): Result6<T1, T2, T3, T4, T5, T6> {
                return Result6(p1, p2, p3, p4, p5, p6)
            }
        })
}


data class Result7<out T1, out T2, out T3, out T4, out T5, out T6, out T7>(
    val t1: T1, val t2: T2, val t3: T3, val t4: T4, val t5: T5, val t6: T6, val t7: T7
)

fun <T1, T2, T3, T4, T5, T6, T7> combineLatest(
    o1: ObservableSource<T1>,
    o2: ObservableSource<T2>,
    o3: ObservableSource<T3>,
    o4: ObservableSource<T4>,
    o5: ObservableSource<T5>,
    o6: ObservableSource<T6>,
    o7: ObservableSource<T7>
): ObservableSource<Result7<T1, T2, T3, T4, T5, T6, T7>> {
    return Observable.combineLatest(o1,
        o2,
        o3,
        o4,
        o5,
        o6,
        o7,
        object : Function7<T1, T2, T3, T4, T5, T6, T7, Result7<T1, T2, T3, T4, T5, T6, T7>> {
            override fun invoke(
                p1: T1, p2: T2, p3: T3, p4: T4, p5: T5, p6: T6, p7: T7
            ): Result7<T1, T2, T3, T4, T5, T6, T7> {
                return Result7(p1, p2, p3, p4, p5, p6, p7)
            }
        })
}


data class Result8<out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8>(
    val t1: T1, val t2: T2, val t3: T3, val t4: T4, val t5: T5, val t6: T6, val t7: T7, val t8: T8
)

fun <T1, T2, T3, T4, T5, T6, T7, T8> combineLatest(
    o1: ObservableSource<T1>,
    o2: ObservableSource<T2>,
    o3: ObservableSource<T3>,
    o4: ObservableSource<T4>,
    o5: ObservableSource<T5>,
    o6: ObservableSource<T6>,
    o7: ObservableSource<T7>,
    o8: ObservableSource<T8>
): ObservableSource<Result8<T1, T2, T3, T4, T5, T6, T7, T8>> {
    return Observable.combineLatest(o1,
        o2,
        o3,
        o4,
        o5,
        o6,
        o7,
        o8,
        object :
            Function8<T1, T2, T3, T4, T5, T6, T7, T8, Result8<T1, T2, T3, T4, T5, T6, T7, T8>> {
            override fun invoke(
                p1: T1, p2: T2, p3: T3, p4: T4, p5: T5, p6: T6, p7: T7, p8: T8
            ): Result8<T1, T2, T3, T4, T5, T6, T7, T8> {
                return Result8(p1, p2, p3, p4, p5, p6, p7, p8)
            }
        })
}


data class Result9<out T1, out T2, out T3, out T4, out T5, out T6, out T7, out T8, out T9>(
    val t1: T1, val t2: T2, val t3: T3, val t4: T4, val t5: T5, val t6: T6, val t7: T7, val t8: T8, val t9: T9
)

fun <T1, T2, T3, T4, T5, T6, T7, T8, T9> combineLatest(
    o1: ObservableSource<T1>,
    o2: ObservableSource<T2>,
    o3: ObservableSource<T3>,
    o4: ObservableSource<T4>,
    o5: ObservableSource<T5>,
    o6: ObservableSource<T6>,
    o7: ObservableSource<T7>,
    o8: ObservableSource<T8>,
    o9: ObservableSource<T9>
): ObservableSource<Result9<T1, T2, T3, T4, T5, T6, T7, T8, T9>> {
    return Observable.combineLatest(o1,
        o2,
        o3,
        o4,
        o5,
        o6,
        o7,
        o8,
        o9,
        object :
            Function9<T1, T2, T3, T4, T5, T6, T7, T8, T9, Result9<T1, T2, T3, T4, T5, T6, T7, T8, T9>> {
            override fun invoke(
                p1: T1, p2: T2, p3: T3, p4: T4, p5: T5, p6: T6, p7: T7, p8: T8, p9: T9
            ): Result9<T1, T2, T3, T4, T5, T6, T7, T8, T9> {
                return Result9(p1, p2, p3, p4, p5, p6, p7, p8, p9)
            }
        })
}


